package com.flyco.modules.api;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.flyco.common.api.vo.Result;
import com.flyco.common.constant.CommonConstant;
import com.flyco.common.system.api.ISysBaseAPI;
import com.flyco.common.system.util.JwtUtil;
import com.flyco.common.system.vo.LoginUser;
import com.flyco.common.util.MD5Util;
import com.flyco.common.util.RedisUtil;
import com.flyco.common.util.oConvertUtils;
import com.flyco.modules.system.entity.SysPermission;
import com.flyco.modules.system.entity.SysUser;
import com.flyco.modules.system.service.ISysDepartService;
import com.flyco.modules.system.service.ISysPermissionService;
import com.flyco.modules.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Api(tags = "授权")
@RestController
@RequestMapping("/api/user")
public class StoreUserController {

    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysPermissionService sysPermissionService;
    @Autowired
    private ISysDepartService sysDepartService;
    @Autowired
    @Lazy
    private RedisUtil redisUtil;
    @Autowired
    @Lazy
    private ISysBaseAPI sysBaseAPI;

    /**
     * 根据前台传入的用户名，生成token
     *
     * @param userName
     * @return
     */
    @ApiOperation(value = "授权-根据用户名生成token", notes = "授权-根据用户名生成token")
    @RequestMapping(value = "/getTokenByUserName", method = RequestMethod.GET)
    public Result<?> getTokenByUserName(@RequestParam(name = "userName", required = true) String userName) {
        if (oConvertUtils.isEmpty(userName)) return Result.error("用户名为空");
        SysUser sysUser = sysUserService.getUserByName(userName);
        Result<JSONObject> result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return Result.error(result.getMessage());
        }
        String syspassword = sysUser.getPassword();
        String username = sysUser.getUsername();
        // 生成token
        String token = JwtUtil.sign(username, syspassword);
        String partnerId = JwtUtil.getSessionData("partnerId");
        if (partnerId == null) {
            partnerId = "";
        }
        // 设置token缓存有效时间
        redisUtil.set(partnerId + CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(partnerId + CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        return Result.ok(token);
    }

    @ApiOperation(value = "授权-根据token获取用户信息", notes = "授权-根据token获取用户信息")
    @RequestMapping(value = "/getUserByToken", method = RequestMethod.GET)
    public Result<?> getUserByToken(@RequestParam(name = "token", required = true) String token) {
        String username = JwtUtil.getUsername(token);
        if (username == null) {
            return Result.error("token非法无效!");
        }
        LoginUser loginUser = sysBaseAPI.getUserByNameforStore(username);
        if (loginUser == null) {
            return Result.error("用户不存在!");
        }
        if (loginUser.getStatus() != 1) {
            return Result.error("账号已被锁定,请联系管理员!");
        }
        if (!jwtTokenRefresh(token, username, loginUser.getPassword())) {
            return Result.error("Token失效，请重新登录!");
        }
        return Result.ok(loginUser);
    }

    private boolean jwtTokenRefresh(String token, String userName, String passWord) {
        String partnerId = JwtUtil.getSessionData("partnerId");
        if (partnerId == null) {
            partnerId = "";
        }
        String cacheToken = String.valueOf(redisUtil.get(partnerId + CommonConstant.PREFIX_USER_TOKEN + token));
        if (oConvertUtils.isNotEmpty(cacheToken)) {
            // 校验token有效性
            if (!JwtUtil.verify(cacheToken, userName, passWord)) {
                String newAuthorization = JwtUtil.sign(userName, passWord);
                // 设置超时时间
                redisUtil.set(partnerId + CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization);
                redisUtil.expire(partnerId + CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
                log.info("——————————用户在线操作，更新token保证不掉线—————————jwtTokenRefresh——————— " + token);
            }
            return true;
        }
        return false;
    }

    @ApiOperation(value = "授权-根据token获取用户权限", notes = "授权-根据token获取用户权限")
    @RequestMapping(value = "/getStoreUserPermissionByToken", method = RequestMethod.GET)
    public Result<?> getStoreUserPermissionByToken(@RequestParam(name = "token", required = true) String token,
                                                   @RequestParam(name = "partnerId", required = true) Long partnerId,
                                                   @RequestParam(name = "storeId", required = true) String storeId) {
        if (oConvertUtils.isEmpty(token)) return Result.error("TOKEN不允许为空！");
        String username = JwtUtil.getUsername(token);
        if (username == null) {
            return Result.error("token非法无效!");
        }
        String _sId = String.valueOf(partnerId) + '-' + storeId;
        //List<String> departIds = sysDepartService.queryParentDeparts(storeId);
        List<SysPermission> metaList = sysPermissionService.queryStoreByUser(username, _sId);
        List<String> permissionIds = metaList.stream()
                .filter(r -> Objects.equals(r.getMenuType(), CommonConstant.MENU_TYPE_0) || Objects.equals(r.getMenuType(), CommonConstant.MENU_TYPE_1))
                .map(r -> r.getId()).collect(Collectors.toList());
        JSONObject json = new JSONObject();
        JSONArray menujsonArray = new JSONArray();
        this.getPermissionJsonArray(menujsonArray, metaList, null);
        JSONArray authjsonArray = new JSONArray();
        this.getAuthJsonArray(authjsonArray, metaList);
        //查询所有的权限
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
        query.eq(SysPermission::getDelFlag, CommonConstant.DEL_FLAG_0);
        query.eq(SysPermission::getMenuType, CommonConstant.MENU_TYPE_2);
        //query.eq(SysPermission::getStatus, "1");
        List<SysPermission> allAuthList = sysPermissionService.list(query);
        JSONArray allauthjsonArray = new JSONArray();
        this.getAllAuthJsonArray(allauthjsonArray, allAuthList);
        //路由菜单
        json.put("menu", menujsonArray);
        //按钮权限（用户拥有的权限集合）
        json.put("auth", authjsonArray);
        json.put("permissionIds", permissionIds);
        //全部权限配置集合（按钮权限，访问权限）
        //json.put("allAuth", allauthjsonArray);
        return Result.ok(json);
    }

    /**
     * 获取菜单JSON数组
     *
     * @param jsonArray
     * @param metaList
     * @param parentJson
     */
    private void getPermissionJsonArray(JSONArray jsonArray, List<SysPermission> metaList, JSONObject parentJson) {
        for (SysPermission permission : metaList) {
            if (permission.getMenuType() == null) {
                continue;
            }
            String tempPid = permission.getParentId();
            JSONObject json = getPermissionJsonObject(permission);
            if (json == null) {
                continue;
            }
            if (parentJson == null && oConvertUtils.isEmpty(tempPid)) {
                jsonArray.add(json);
                if (!permission.isLeaf()) {
                    getPermissionJsonArray(jsonArray, metaList, json);
                }
            } else if (parentJson != null && oConvertUtils.isNotEmpty(tempPid) && tempPid.equals(parentJson.getString("id"))) {
                // 类型( 0：一级菜单 1：子菜单 2：按钮 )
                if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_2)) {
                    JSONObject metaJson = parentJson.getJSONObject("meta");
                    if (metaJson.containsKey("permissionList")) {
                        metaJson.getJSONArray("permissionList").add(json);
                    } else {
                        JSONArray permissionList = new JSONArray();
                        permissionList.add(json);
                        metaJson.put("permissionList", permissionList);
                    }
                    // 类型( 0：一级菜单 1：子菜单 2：按钮 )
                } else if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_1) || permission.getMenuType().equals(CommonConstant.MENU_TYPE_0)) {
                    if (parentJson.containsKey("children")) {
                        parentJson.getJSONArray("children").add(json);
                    } else {
                        JSONArray children = new JSONArray();
                        children.add(json);
                        parentJson.put("children", children);
                    }

                    if (!permission.isLeaf()) {
                        getPermissionJsonArray(jsonArray, metaList, json);
                    }
                }
            }

        }
    }

    /**
     * 根据菜单配置生成路由json
     *
     * @param permission
     * @return
     */
    private JSONObject getPermissionJsonObject(SysPermission permission) {
        JSONObject json = new JSONObject();
        // 类型(0：一级菜单 1：子菜单 2：按钮)
        if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_2)) {
            json.put("action", permission.getPerms());
            json.put("type", permission.getPermsType());
            json.put("describe", permission.getName());
            //return null;
        } else if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_0) || permission.getMenuType().equals(CommonConstant.MENU_TYPE_1)) {
            json.put("id", permission.getId());
            if (permission.isRoute()) {
                json.put("route", "1");// 表示生成路由
            } else {
                json.put("route", "0");// 表示不生成路由
            }

            if (isWWWHttpUrl(permission.getUrl())) {
                json.put("path", MD5Util.MD5Encode(permission.getUrl(), "utf-8"));
            } else {
                json.put("path", permission.getUrl());
            }

            // 重要规则：路由name (通过URL生成路由name,路由name供前端开发，页面跳转使用)
            if (oConvertUtils.isNotEmpty(permission.getComponentName())) {
                json.put("name", permission.getComponentName());
            } else {
                json.put("name", urlToRouteName(permission.getUrl()));
            }

            // 是否隐藏路由，默认都是显示的
            if (permission.isHidden()) {
                json.put("hidden", true);
            }
            // 聚合路由
            if (permission.isAlwaysShow()) {
                json.put("alwaysShow", true);
            }
            json.put("component", permission.getComponent());
            JSONObject meta = new JSONObject();
            // 由用户设置是否缓存页面 用布尔值
            if (permission.isKeepAlive()) {
                meta.put("keepAlive", true);
            } else {
                meta.put("keepAlive", false);
            }

            /*update_begin author:wuxianquan date:20190908 for:往菜单信息里添加外链菜单打开方式 */
            //外链菜单打开方式
            if (permission.isInternalOrExternal()) {
                meta.put("internalOrExternal", true);
            } else {
                meta.put("internalOrExternal", false);
            }
            /* update_end author:wuxianquan date:20190908 for: 往菜单信息里添加外链菜单打开方式*/

            meta.put("title", permission.getName());
            if (oConvertUtils.isEmpty(permission.getParentId())) {
                // 一级菜单跳转地址
                json.put("redirect", permission.getRedirect());
                if (oConvertUtils.isNotEmpty(permission.getIcon())) {
                    meta.put("icon", permission.getIcon());
                }
            } else {
                if (oConvertUtils.isNotEmpty(permission.getIcon())) {
                    meta.put("icon", permission.getIcon());
                }
            }
            if (isWWWHttpUrl(permission.getUrl())) {
                meta.put("url", permission.getUrl());
            }
            json.put("meta", meta);
        }

        return json;
    }

    /**
     * 获取权限JSON数组
     *
     * @param jsonArray
     * @param metaList
     */
    private void getAuthJsonArray(JSONArray jsonArray, List<SysPermission> metaList) {
        for (SysPermission permission : metaList) {
            if (permission.getMenuType() == null) {
                continue;
            }
            JSONObject json = null;
            if (permission.getMenuType().equals(CommonConstant.MENU_TYPE_2) && CommonConstant.STATUS_1.equals(permission.getStatus())) {
                json = new JSONObject();
                json.put("action", permission.getPerms());
                json.put("type", permission.getPermsType());
                json.put("describe", permission.getName());
                jsonArray.add(json);
            }
        }
    }

    /**
     * 获取权限JSON数组
     *
     * @param jsonArray
     * @param allList
     */
    private void getAllAuthJsonArray(JSONArray jsonArray, List<SysPermission> allList) {
        JSONObject json = null;
        for (SysPermission permission : allList) {
            json = new JSONObject();
            json.put("action", permission.getPerms());
            json.put("status", permission.getStatus());
            json.put("type", permission.getPermsType());
            json.put("describe", permission.getName());
            jsonArray.add(json);
        }
    }

    /**
     * 判断是否外网URL 例如： http://localhost:8080/swagger-ui.html#/ 支持特殊格式： {{
     * window._CONFIG['domianURL'] }}/druid/ {{ JS代码片段 }}，前台解析会自动执行JS代码片段
     *
     * @return
     */
    private boolean isWWWHttpUrl(String url) {
        if (url != null && (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("{{"))) {
            return true;
        }
        return false;
    }

    /**
     * 通过URL生成路由name（去掉URL前缀斜杠，替换内容中的斜杠‘/’为-） 举例： URL = /isystem/role RouteName =
     * isystem-role
     *
     * @return
     */
    private String urlToRouteName(String url) {
        if (oConvertUtils.isNotEmpty(url)) {
            if (url.startsWith("/")) {
                url = url.substring(1);
            }
            url = url.replace("/", "-");

            // 特殊标记
            url = url.replace(":", "@");
            return url;
        } else {
            return null;
        }
    }
}
